package cn.icanci.loopstack.ddk.admin.biz.service.impl;

import cn.icanci.loopstack.ddk.admin.biz.mapping.config.NoticeConfigMapping;
import cn.icanci.loopstack.ddk.admin.biz.service.BaseService;
import cn.icanci.loopstack.ddk.admin.biz.service.ExceptionHolder;
import cn.icanci.loopstack.ddk.admin.biz.service.NoticeConfigService;
import cn.icanci.loopstack.ddk.admin.dal.mapper.entity.NoticeConfigDO;
import cn.icanci.loopstack.ddk.admin.dal.mapper.mapper.NoticeConfigMapper;
import cn.icanci.loopstack.ddk.common.model.PageList;
import cn.icanci.loopstack.ddk.common.model.Paginator;
import cn.icanci.loopstack.ddk.common.model.config.NoticeConfigVO;
import cn.icanci.loopstack.ddk.common.utils.PaginatorUtils;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

/**
 * @author icanci
 * @since 1.0 Created in 2023/01/06 21:07
 */
@Service
public class NoticeConfigServiceImpl extends BaseService<NoticeConfigVO> implements NoticeConfigService {

    private static final Logger   logger = LoggerFactory.getLogger(NoticeConfigServiceImpl.class);

    @Resource
    private NoticeConfigMapper    noticeConfigMapper;
    @Resource
    private NoticeConfigMapping   noticeConfigMapping;
    @Resource
    protected TransactionTemplate transactionTemplate;

    @Override
    public PageList<List<NoticeConfigVO>> queryPage(NoticeConfigVO vo, int currentPage, int pageSize) {
        NoticeConfigDO noticeConfig = new NoticeConfigDO();
        noticeConfig.setEnv(getEnv());
        List<NoticeConfigVO> noticeConfigList = noticeConfigMapping.dos2vos(noticeConfigMapper.selectList(noticeConfig));
        if (CollectionUtils.isEmpty(noticeConfigList)) {
            return new PageList<>(Lists.newArrayList(), new Paginator(0, pageSize, currentPage));
        }
        Map<String, List<NoticeConfigVO>> noticeConfigMap = noticeConfigList.stream().collect(Collectors.groupingBy(NoticeConfigVO::getNoticeConfigResource));

        currentPage = Math.max(currentPage - 1, 0);

        List<List<NoticeConfigVO>> ret = noticeConfigMap.values().stream().skip(currentPage).limit(pageSize).collect(Collectors.toList());
        return PaginatorUtils.formatPaginator(ret, currentPage, pageSize, noticeConfigMap.values().size());
    }

    @Override
    public void save(List<NoticeConfigVO> newNoticeConfigList, List<String> appUuid) {
        // 针对集合的需要特殊处理，通过唯一资源进行数据的更新删除插入处理。不根据数据库id
        if (CollectionUtils.isEmpty(newNoticeConfigList)) {
            return;
        }

        NoticeConfigVO noticeConfig = newNoticeConfigList.iterator().next();
        String noticeConfigResource = noticeConfig.getNoticeConfigResource();
        List<NoticeConfigVO> oldNoticeConfigList = noticeConfigMapping.dos2vos(noticeConfigMapper.queryByNoticeConfigResource(noticeConfigResource, getEnv()));

        Map<String, NoticeConfigVO> newMap = newNoticeConfigList.stream().collect(Collectors.toMap(NoticeConfigVO::getAppUuid, x -> x));
        Map<String, NoticeConfigVO> oldMap = oldNoticeConfigList.stream().collect(Collectors.toMap(NoticeConfigVO::getAppUuid, x -> x));

        // 全部 appUuid
        Set<String> uuids = Sets.newHashSet(appUuid);
        uuids.addAll(oldNoticeConfigList.stream().map(NoticeConfigVO::getAppUuid).collect(Collectors.toList()));

        final ExceptionHolder holder = new ExceptionHolder();
        // 使用声明式事务
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                try {
                    for (String uuid : uuids) {
                        // 数据库有，但是新的vo没有，删除
                        if (oldMap.get(uuid) != null && newMap.get(uuid) == null) {
                            noticeConfigMapper.delete(oldMap.get(uuid).getId());
                        }
                        // 数据库有，新的vo也有，更新
                        if (oldMap.get(uuid) != null && newMap.get(uuid) != null) {
                            NoticeConfigVO noticeConfigVO = newMap.get(uuid);
                            beforeUpdate(noticeConfigVO);
                            noticeConfigMapper.update(noticeConfigMapping.vo2do(noticeConfigVO));
                        }
                        // 数据库没有，则插入
                        if (oldMap.get(uuid) == null && newMap.get(uuid) != null) {
                            NoticeConfigVO noticeConfigVO = newMap.get(uuid);
                            beforeInsert(noticeConfigVO);
                            noticeConfigMapper.insert(noticeConfigMapping.vo2do(noticeConfigVO));
                        }
                        // 数据库没有，并且新的vo也没有 无需操作 这种情况不可能出现~~~
                        // no op
                    }
                } catch (Exception e) {
                    logger.error("[NoticeConfigService][save] 保存异常，事务回滚");
                    status.setRollbackOnly();
                    holder.setException(e);
                }
            }
        });

        if (holder.getException() != null) {
            throw new RuntimeException(holder.getException());
        }
    }

    @Override
    public List<NoticeConfigVO> queryByNoticeConfigName(String noticeConfigName) {
        return noticeConfigMapping.dos2vos(noticeConfigMapper.queryByNoticeConfigName(noticeConfigName, getEnv()));
    }

    @Override
    public List<NoticeConfigVO> queryByNoticeConfigResource(String noticeConfigResource) {
        return noticeConfigMapping.dos2vos(noticeConfigMapper.queryByNoticeConfigResource(noticeConfigResource, getEnv()));
    }

    @Override
    public List<NoticeConfigVO> queryByAppUuid(String appUuid, Integer isDelete) {
        return noticeConfigMapping.dos2vos(noticeConfigMapper.queryByAppUuid(appUuid, isDelete, getEnv()));
    }
}
